#include "UrlConverter.h"

unsigned char UrlConverter::_hexCharToInt8(char c) {
    if(c >= 'a' && c <= 'f') {
        return c - 'a' + 10;
    }
    if(c >= 'A' && c <= 'F') {
        return c - 'A' + 10;
    }
    if(c >= '0' && c <= '9') {
        return c - '0';
    }
    PrintLine("非法字符 [%c]", c);
    return -1;
}

std::string UrlConverter::_int8ToHexChar(unsigned char c) {
    char list[] = "0123456789ABCDEF";   // 用于转换的字符列表
    std::string ret = "";

    /*转换思路：
    // 八位二进制数：0110 1010
    // 两位十六进制：  6   A
    // 01101010(2) == 106(10) == 6A(16)
    // 106/16 == 6，106 % 16 == 10
    // 在list列表中，下标6对应的是6，下标10对应的是A
    // 所以用以上计算结果查表即可完成字符转换
    */
    ret += list[c / 16];    // 只保留高四位（整数部分）
    ret += list[c % 16];    // 只保留低四位（小数部分）
    return ret;
}

std::string UrlConverter::_convertFromUrl(std::string url) {
    std::string ret = "";
    for (int i = 0; i < url.length(); i++) {
        // 遇到%，就把它后面的两个十六进制字符转成二进制字符
        if('%' == url[i]) {
            // 如果url[i] = 6A
            // 先得到高四位0110，但转换结果在低四位上
            // 0000 0110
            // 左移4位，把高四位左移至高四位（最终位置），低四位自动补0
            // 0110 0000
            unsigned char c = _hexCharToInt8(url[i + 1]);
            c = c << 4;
            // 再得到低四位1010，与高四位结果相加
            // 0110 1010
            c += _hexCharToInt8(url[i + 2]);
            ret += c;   // 保存转换结果
            i += 2;     // 跳过%后的两位十六进制字符
        }
        else {
            ret += url[i];
        }
    }
    return ret;
}

std::string UrlConverter::_convertToUrl(std::string str) {
    std::string ret = "";
    // todo：具体哪些该转，哪些不该转可以百度
    // 这里的做法是，除了（0~9、a~z、A~Z、.、/、_、-），通通转成十六进制字符，浏览器都可以识别的
    for (int i = 0; i < str.length(); i++) {
        // 0~9、a~z、A~Z、.、/、_、- 不用转换
        if(std::isalnum(str[i]) || '_' == str[i] || '-' == str[i] || '.' == str[i] || '/' == str[i]) {
            ret += str[i];
        }
        else {
            ret += "%";
            ret += _int8ToHexChar(str[i]);
        }
    }
    return ret;
}